package com.example.software.filter;

import com.example.software.util.JwtTokenUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;
import java.util.Enumeration;

@Slf4j
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        // 详细记录请求信息，用于调试
        String uri = request.getRequestURI();
        String method = request.getMethod();
        log.info("接收到请求 - URI: {}, Method: {}", uri, method);
        
        // 获取token并预记录
        String authHeader = request.getHeader(jwtTokenUtil.getHeaderName());
        boolean hasToken = authHeader != null && authHeader.startsWith(jwtTokenUtil.getTokenPrefix());
        log.info("请求是否携带token: {}", hasToken);
        
        // 创建任务的POST请求特殊处理
        boolean isTaskCreate = method.equals("POST") && uri.equals("/api/tasks");
        if (isTaskCreate) {
            log.info("检测到任务创建请求，需要企业用户权限");
            // 未提供token的情况，直接返回401
            if (!hasToken) {
                log.error("任务创建请求未提供认证令牌");
                writeErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, "创建任务需要认证，请先登录");
                return;
            }
        }
        
        // 检查是否是允许匿名访问的路径
        boolean isPermitAllPath = isPermitAllPath(uri, method);
        if (isPermitAllPath) {
            log.debug("URL {} 允许匿名访问，跳过认证", uri);
            chain.doFilter(request, response);
            return;
        }
        
        // 记录所有请求头
        if (log.isDebugEnabled()) {
            logRequestHeaders(request);
        }
        
        // 没有提供token的请求
        if (!hasToken) {
            log.error("请求未携带有效的Authorization头，返回401错误");
            writeErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, "需要认证令牌");
            return;
        }
        
        // 处理有token的请求
        String token = null;
        try {
            token = authHeader.substring(jwtTokenUtil.getTokenPrefix().length()).trim();
            if (token.isEmpty()) {
                log.error("提取的token为空");
                writeErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, "认证令牌为空");
                return;
            }
            
            log.debug("提取到的Token: {}", token.length() > 10 ? token.substring(0, 10) + "..." : token);
            
            // 先检查token是否已过期
            if (jwtTokenUtil.isTokenExpired(token)) {
                log.error("提供的令牌已过期");
                writeErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, "认证令牌已过期，请重新登录");
                return;
            }
            
            // 解析token
            Claims claims = jwtTokenUtil.parseToken(token);
            log.debug("解析的Claims: {}", claims);
            
            // 尝试不同方式获取userId
            Long userId = extractUserId(claims);
            String userType = extractUserType(claims);
            String username = claims.get("username", String.class);
            
            // 检查userType是否为null
            if (userType == null) {
                log.error("JWT认证失败：Token中userType为null");
                writeErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, "Invalid token: missing user type");
                return;
            }
            
            // 检查创建任务的权限
            if (isTaskCreate && !"company".equals(userType)) {
                log.error("权限不足：非企业用户({})尝试创建任务", userType);
                writeErrorResponse(response, HttpServletResponse.SC_FORBIDDEN, "只有企业用户才能发布任务");
                return;
            }
            
            log.info("JWT认证成功 - 用户ID: {}, 用户名: {}, 用户类型: {}", userId, username, userType);
            
            // 将用户信息添加到请求属性中，方便Controller使用
            request.setAttribute("userId", userId);
            request.setAttribute("userType", userType);
            
            // 为用户添加基于角色的权限
            String role = "ROLE_" + userType.toUpperCase();
            SimpleGrantedAuthority authority = new SimpleGrantedAuthority(role);
            
            // 创建认证对象
            UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
                    userId,
                    null, // 无凭证，因为我们使用的是JWT
                    Collections.singletonList(authority)
            );
            
            // 设置认证详情，包括用户类型和用户名
            authToken.setDetails(Collections.singletonMap("userType", userType));
            
            // 设置到SecurityContextHolder
            SecurityContextHolder.getContext().setAuthentication(authToken);
            log.debug("已将认证信息设置到SecurityContextHolder");
            
            chain.doFilter(request, response);
        } catch (io.jsonwebtoken.ExpiredJwtException e) {
            log.error("JWT令牌已过期: {}", e.getMessage());
            writeErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, "认证令牌已过期，请重新登录");
            // 确保清除任何可能的认证信息
            SecurityContextHolder.clearContext();
        } catch (io.jsonwebtoken.SignatureException e) {
            log.error("JWT签名验证失败: {}", e.getMessage());
            writeErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, "无效的认证令牌: 签名验证失败");
            SecurityContextHolder.clearContext();
        } catch (io.jsonwebtoken.MalformedJwtException e) {
            log.error("JWT格式不正确: {}", e.getMessage());
            writeErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, "无效的认证令牌: 格式不正确");
            SecurityContextHolder.clearContext();
        } catch (Exception e) {
            log.error("JWT认证失败: {}", e.getMessage());
            writeErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, "无效的认证令牌: " + e.getMessage());
            SecurityContextHolder.clearContext();
        }
    }
    
    /**
     * 从claims中提取userId，尝试多种获取方式
     */
    private Long extractUserId(Claims claims) {
        // 尝试从userId字段获取
        Object userIdObj = claims.get("userId");
        if (userIdObj != null) {
            log.debug("从claims.userId获取到用户ID: {}", userIdObj);
            return Long.valueOf(userIdObj.toString());
        }
        
        // 尝试从subject获取
        String subject = claims.getSubject();
        if (subject != null) {
            log.debug("从claims.subject获取到用户ID: {}", subject);
            return Long.valueOf(subject);
        }
        
        // 尝试从sub获取
        Object subObj = claims.get("sub");
        if (subObj != null) {
            log.debug("从claims.sub获取到用户ID: {}", subObj);
            return Long.valueOf(subObj.toString());
        }
        
        log.error("无法从token中获取用户ID");
        throw new RuntimeException("无法从token中获取用户ID");
    }
    
    /**
     * 从claims中提取userType，尝试多种获取方式
     */
    private String extractUserType(Claims claims) {
        // 尝试标准方式获取
        String userType = claims.get("userType", String.class);
        if (userType != null) {
            return userType;
        }
        
        // 尝试直接获取对象然后转换
        Object userTypeObj = claims.get("userType");
        if (userTypeObj != null) {
            return userTypeObj.toString();
        }
        
        return null;
    }
    
    /**
     * 将错误信息写入响应
     */
    private void writeErrorResponse(HttpServletResponse response, int status, String message) throws IOException {
        response.setStatus(status);
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        response.getWriter().write("{\"error\":\"" + message + "\"}");
    }
    
    /**
     * 记录请求头信息
     */
    private void logRequestHeaders(HttpServletRequest request) {
        log.debug("请求头信息:");
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            String headerValue = request.getHeader(headerName);
            // 如果是Authorization头，只打印前20个字符
            if ("authorization".equalsIgnoreCase(headerName) && headerValue != null && headerValue.length() > 20) {
                log.debug("Header {} : {}", headerName, headerValue.substring(0, 20) + "...");
            } else {
                log.debug("Header {} : {}", headerName, headerValue);
            }
        }
    }
    
    /**
     * 检查是否是允许匿名访问的路径
     */
    private boolean isPermitAllPath(String uri, String method) {
        // 登录注册相关接口允许匿名访问
        if (uri.startsWith("/api/auth/")) {
            return true;
        }
        
        // GET任务列表允许匿名访问
        if (method.equals("GET") && uri.equals("/api/tasks")) {
            return true;
        }
        
        return false;
    }
} 